package ciyuanwutuobang;

import ciyuanwutuobang.Core.PlayerManager;
import ciyuanwutuobang.Entity.FastType;
import ciyuanwutuobang.Entity.PlayerInfo;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;

import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author 150149
 */
public class AntiCE implements Listener {
    private Map<String, Boolean> IsDamage = new HashMap<>();
    private ScheduledExecutorService checkThreadPool = Executors.newScheduledThreadPool(10);
    private PlayerManager playerManager;

    public AntiCE(PlayerManager playerManager) {
        this.playerManager = playerManager;
        Player[] l = Bukkit.getServer().getOnlinePlayers().toArray(new Player[0]);
        for (Player pl : l) {
            if (!playerManager.containsPlayerInfo(pl)) {
                MainClass.debug("热重载 开始run");
                runCheck(pl);
            }
        }
    }

    @EventHandler
    public void onJoin(PlayerJoinEvent event) {
        if (event.getPlayer().getName().contains("LOTR")) {
            return;
        }
        if (!playerManager.containsPlayerInfo(event.getPlayer())) {
            playerManager.setOnline(event.getPlayer(), true);
            runCheck(event.getPlayer());
            MainClass.debug("Join 开始run");
        } else {
            playerManager.setOnline(event.getPlayer(), true);
            MainClass.debug("存在玩家，不开启线程");
        }
    }

    @EventHandler
    public void onLeave(PlayerQuitEvent event) {
        playerManager.setOnline(event.getPlayer(), false);
        MainClass.debug("玩家离线，设置状态false");
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false)
    public void onMove(PlayerMoveEvent event) {
        if (event.getPlayer().getName().contains("LOTR")) {
            return;
        }
        PlayerInfo playerInfo = playerManager.getPlayerInfo(event.getPlayer());
        playerInfo.MoveCount = playerInfo.MoveCount + 1;
    }

    private boolean isHoldSpecialItem(Player player) {
        for (int itemId : MainClass.self.config.special_items) {
            if (player.getItemInHand().getTypeId()==itemId) {
                return true;
            }
        }
        return false;
    }

    private void updatePlayerInfo(PlayerInfo playerInfo) {
        if (playerInfo.lastloc == null) {
            playerInfo.lastloc = playerInfo.player.getLocation();
        }
        if (playerInfo.lastloc.getWorld().equals(playerInfo.player.getLocation().getWorld()) && MainClass.lasttime != 0) {
            playerInfo.speed = playerInfo.player.getLocation().distance(playerInfo.lastloc);
        }
        MainClass.lasttime = System.currentTimeMillis();
    }

    private boolean checkPacket(PlayerInfo playerInfo) {
        long current = System.currentTimeMillis();
        if (playerInfo.MoveCount >= MainClass.self.config.max_move_packet_count && playerInfo.MoveCount < 1000) {
            if (current - playerInfo.MoveTimer <= 1500) {
                if (playerInfo.KickTime >= 3) {
                    playerInfo.player.sendMessage("§8[ §c反变速 §8]§7 你的数据包异常，请停止变速行为，若无请忽略该信息(提醒次数" + playerInfo.KickTime + "/" + MainClass.self.config.max_kick_count + ")");
                }
                sendMessage(playerInfo, FastType.PACKET);
                return true;
            }
            playerInfo.MoveTimer = current;
        }
        return false;
    }

    private void addCounter(PlayerInfo playerInfo) {
        playerInfo.CheckTime = 30;
        playerInfo.KickTime = playerInfo.KickTime + 1;

        if (playerInfo.KickTime == MainClass.self.config.max_kick_count) {
            MainClass.self.broadcast(playerInfo.player);
        }
    }

    private boolean checkVehicle(PlayerInfo playerInfo) {
        long current = System.currentTimeMillis();
        if (playerInfo.speed > MainClass.self.config.max_drive_kick_speed && playerInfo.speed < 100 && playerInfo.player.getVehicle() != null && !playerInfo.player.isFlying() && !isHoldSpecialItem(playerInfo.player)) {
            if (playerInfo.timer != 0) {
                if (current - playerInfo.timer <= 1500) {
                    sendMessage(playerInfo, FastType.DRIVE);
                    return true;
                }
            }
            playerInfo.timer = current;
        }
        return false;
    }

    private boolean checkSwim(PlayerInfo playerInfo) {
        long current = System.currentTimeMillis();
        if (playerInfo.speed > MainClass.self.config.max_swim_kick_speed && playerInfo.speed < 100 && playerInfo.player.getVehicle() == null && (playerInfo.player.getLocation().getBlock().getType().equals(Material.WATER_LILY)
                || playerInfo.player.getLocation().getBlock().getType().equals(Material.STATIONARY_WATER)) && (playerInfo.player.getLocation().add(0, -1, 0).getBlock().getType().equals(Material.WATER_LILY)
                || playerInfo.player.getLocation().add(0, -1, 0).getBlock().getType().equals(Material.STATIONARY_WATER)) && !isHoldSpecialItem(playerInfo.player)
                && playerInfo.lastloc.getY() - playerInfo.player.getLocation().getY() < MainClass.self.config.ignore_when_y_move && !playerInfo.player.isFlying()) {
            if (playerInfo.timer != 0) {
                if (current - playerInfo.timer <= 1500) {
                    sendMessage(playerInfo, FastType.SWIM);
                    return true;
                }
            }
            playerInfo.timer = current;
        }
        return false;
    }

    private boolean checkWalkOnIce(PlayerInfo playerInfo) {
        long current = System.currentTimeMillis();
        if (playerInfo.speed > MainClass.self.config.max_ice_kick_speed && playerInfo.speed < 100 && playerInfo.player.getVehicle() == null
                && (playerInfo.player.getLocation().add(0, -1, 0).getBlock().getType().name().toLowerCase().contains("ice") ||
                playerInfo.player.getLocation().add(0, -2, 0).getBlock().getType().name().toLowerCase().contains("ice") ||
                playerInfo.player.getLocation().add(0, -3, 0).getBlock().getType().name().toLowerCase().contains("ice") )
                && !isHoldSpecialItem(playerInfo.player)
                && playerInfo.lastloc.getY() - playerInfo.player.getLocation().getY() < MainClass.self.config.ignore_when_y_move && !playerInfo.player.isFlying()) {
            if (playerInfo.timer != 0) {
                if (current - playerInfo.timer <= 1500) {
                    sendMessage(playerInfo, FastType.ICE);
                    return true;
                }
            }
            playerInfo.timer = current;
        }
        return false;
    }

    private boolean checkWalk(PlayerInfo playerInfo) {
        long current = System.currentTimeMillis();
        if (playerInfo.speed > MainClass.self.config.max_walk_kick_speed && playerInfo.speed < 100 && playerInfo.player.getVehicle() == null && !isHoldSpecialItem(playerInfo.player)
                && !(playerInfo.player.getLocation().add(0, -1, 0).getBlock().getType().name().toLowerCase().contains("ice") ||
                playerInfo.player.getLocation().add(0, -2, 0).getBlock().getType().name().toLowerCase().contains("ice") ||
                playerInfo.player.getLocation().add(0, -3, 0).getBlock().getType().name().toLowerCase().contains("ice") )
                && playerInfo.lastloc.getY() - playerInfo.player.getLocation().getY() < MainClass.self.config.ignore_when_y_move && !playerInfo.player.isFlying()) {
            if (playerInfo.timer != 0) {
                if (current - playerInfo.timer <= 1500) {
                    sendMessage(playerInfo, FastType.WALK);
                    return true;
                }
            }
            playerInfo.timer = current;
        }
        return false;
    }

    private boolean checkSpecialItems(PlayerInfo playerInfo) {
        for (int itemId : MainClass.self.config.special_items) {
            long current = System.currentTimeMillis();
            if (playerInfo.player.getItemInHand().getTypeId() == itemId) {
                int index = MainClass.self.config.special_items.indexOf(itemId);
                if (index < MainClass.self.config.max_special_items_speed.size() && playerInfo.speed > MainClass.self.config.max_special_items_speed.get(index)
                        && playerInfo.speed < 100 && playerInfo.lastloc.getY() - playerInfo.player.getLocation().getY() < MainClass.self.config.ignore_when_y_move && !playerInfo.player.isFlying()) {
                    if (playerInfo.timer != 0) {
                        if (current - playerInfo.timer <= 1500) {
                            sendMessage(playerInfo, FastType.SPECIAL_ITEM);
                            return true;
                        }
                    }
                    playerInfo.timer = current;
                }
            }
        }
        return false;
    }

    private void testModeSendMsg(PlayerInfo playerInfo) {
        if (!"".equals(MainClass.testPlayer) && playerInfo.player.getName().equals(MainClass.testPlayer)) {
            DecimalFormat d2 = new DecimalFormat("######0.00");
            MainClass.self.sendToOP("§8[ §c次元反变速 §8]§7 玩家 §a" + playerInfo.player.getName() + " §7当前速度 §a" + d2.format(playerInfo.speed));
        }
    }

    private void clearOrKick(PlayerInfo playerInfo) {
        if (playerInfo.KickTime >= MainClass.self.config.max_kick_count) {
            playerInfo.beenKickCount++;
            MainClass.self.kickCountManager.setKickCount(playerInfo);
            if (playerInfo.beenKickCount>=MainClass.self.config.max_ban_count) {
                MainClass.handleBanPlayer(playerInfo.player);
            } else {
                MainClass.handleViolection(playerInfo.player);
            }
            playerInfo.KickTime = 0;
            playerInfo.CheckTime = 0;
        }
        if (playerInfo.CheckTime <= 0) {
            playerInfo.KickTime = 0;
            playerInfo.CheckTime = 0;
        }
        playerInfo.MoveCount = 0;
        playerManager.setPlayerInfo(playerInfo);
    }

    public void runCheck(Player player) {
        playerManager.putTask(player, checkThreadPool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                try {
                    PlayerInfo playerInfo = playerManager.getPlayerInfo(player);
                    MainClass.debug("监测玩家：" + playerInfo.player.getName() + " 在线状态：" + playerManager.isOnline(player));
                    if (!playerManager.isOnline(player)) {
                        playerManager.removePlayer(playerInfo.player);
                        MainClass.debug("玩家不在线，取消线程");
                        playerManager.stopTask(player);
                        return;
                    }

                    updatePlayerInfo(playerInfo);
                    boolean isCount = false;
                    if (checkPacket(playerInfo)) {
                        addCounter(playerInfo);
                        isCount = true;
                    }

                    if (playerInfo.lastloc.getWorld().equals(playerInfo.player.getLocation().getWorld()) && !isCount) {
                        IsDamage.putIfAbsent(playerInfo.player.getName(), false);
                        if (IsDamage.get(playerInfo.player.getName())) {
                            IsDamage.put(playerInfo.player.getName(), false);
                        }

                        if (checkVehicle(playerInfo) || checkSwim(playerInfo) || checkWalkOnIce(playerInfo) || checkWalk(playerInfo) || checkSpecialItems(playerInfo)) {
                            addCounter(playerInfo);
                        }
                    }

                    playerInfo.lastloc = playerInfo.player.getLocation();
                    testModeSendMsg(playerInfo);
                    clearOrKick(playerInfo);
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            }

        }, 1L, 1000L, TimeUnit.MILLISECONDS));
    }

    @EventHandler
    public void onDamage(EntityDamageEvent event) {
        if (event.getEntity() instanceof Player) {
            Player p = (Player) event.getEntity();
            if (p.getName().contains("LOTR")) {
                return;
            }
            IsDamage.put(p.getName(), true);
        }
    }

    private void sendMessage(PlayerInfo playerInfo, FastType type) {
        String head = "§8[ §c次元反变速 §8]§7";
        String kickCountMsg = "§7(提醒次数§a" + playerInfo.KickTime + "§7/§a" + MainClass.self.config.max_kick_count + "§7)";
        String kickCountMsgNoColor = "(提醒次数" + playerInfo.KickTime + "/" + MainClass.self.config.max_kick_count + ")";
        DecimalFormat d2 = new DecimalFormat("######0.00");
        if (type == FastType.PACKET) {
            MainClass.self.sendToOP(head + "玩家 §a" + playerInfo.player.getPlayerListName() + " §7发送过多移动数据包(§a" + playerInfo.MoveCount + "§7)" + kickCountMsg);
            Bukkit.getConsoleSender().sendMessage(head + "玩家 §a" + playerInfo.player.getPlayerListName() + " §7发送过多移动数据包(§a" + playerInfo.MoveCount + "§7)" + kickCountMsg);
            MainClass.self.logInfo(playerInfo.player.getPlayerListName() + " 发送过多移动数据包(" + playerInfo.MoveCount + ")" + kickCountMsgNoColor);
        } else if (type == FastType.DRIVE) {
            MainClass.self.sendToOP(head + "玩家乘坐载具 §a" + playerInfo.player.getName() + " §7移速过快,速度 §a" + d2.format(playerInfo.speed) + kickCountMsg);
            Bukkit.getConsoleSender().sendMessage(head + "玩家乘坐载具 §a" + playerInfo.player.getName() + " §7移速过快,速度 §a" + d2.format(playerInfo.speed) + kickCountMsg);
            MainClass.self.logInfo(playerInfo.player.getName() + " 乘坐载具移速过快,速度 " + d2.format(playerInfo.speed) + kickCountMsgNoColor);
        } else if (type == FastType.SWIM) {
            MainClass.self.sendToOP(head + "玩家游泳 §a" + playerInfo.player.getName() + " §7移速过快,速度 §a" + d2.format(playerInfo.speed) + kickCountMsg);
            Bukkit.getConsoleSender().sendMessage(head + "玩家游泳 §a" + playerInfo.player.getName() + " §7移速过快,速度 §a" + d2.format(playerInfo.speed) + kickCountMsg);
            MainClass.self.logInfo(playerInfo.player.getName() + " 游泳移速过快,速度 " + d2.format(playerInfo.speed) + kickCountMsgNoColor);
        } else if (type == FastType.ICE) {
            MainClass.self.sendToOP(head + "玩家溜冰 §a" + playerInfo.player.getName() + " §7移速过快,速度 §a" + d2.format(playerInfo.speed) + kickCountMsg);
            Bukkit.getConsoleSender().sendMessage(head + "玩家溜冰 §a" + playerInfo.player.getName() + " §7移速过快,速度 §a" + d2.format(playerInfo.speed) + kickCountMsg);
            MainClass.self.logInfo(playerInfo.player.getName() + " 溜冰移速过快,速度 " + d2.format(playerInfo.speed) + kickCountMsgNoColor);
        } else if (type == FastType.WALK) {
            MainClass.self.sendToOP(head + "玩家步行 §a" + playerInfo.player.getName() + " §7移速过快,速度 §a" + d2.format(playerInfo.speed) + kickCountMsg);
            Bukkit.getConsoleSender().sendMessage(head + "玩家步行 §a" + playerInfo.player.getName() + " §7移速过快,速度 §a" + d2.format(playerInfo.speed) + kickCountMsg);
            MainClass.self.logInfo(playerInfo.player.getName() + " 步行移速过快,速度 " + d2.format(playerInfo.speed) + kickCountMsgNoColor);
        } else if (type == FastType.SPECIAL_ITEM) {
            MainClass.self.sendToOP(head + "玩家 §a" + playerInfo.player.getName() + " §7手持物品 §a" + playerInfo.player.getItemInHand().getTypeId() + " §7移速过快,速度 §a" + d2.format(playerInfo.speed) + kickCountMsg);
            Bukkit.getConsoleSender().sendMessage(head + "玩家 §a" + playerInfo.player.getName() + " §7手持物品 §a" + playerInfo.player.getItemInHand().getTypeId() + " §7移速过快,速度 §a" + d2.format(playerInfo.speed) + kickCountMsg);
            MainClass.self.logInfo(playerInfo.player.getName() + " 手持物品 " + playerInfo.player.getItemInHand().getTypeId() + " 移速过快,速度 " + d2.format(playerInfo.speed) + kickCountMsgNoColor);
        }
    }
}
